'''
Created on Nov 22, 2009

@author: david
'''
import traceback

# Labels
ERROR_TYPES = ("None", "Response", "Question", "Survey", "Order", "Slot", "Report", "Download")
ERROR_LEVELS = ("None", "Debug", "Info", "Warning", "Error", "Critical")
ERROR_STATES = ("None", "Logged", "Notified", "Acknowledged", "Resolved", "Canceled")

# Error States
STATE_LOGGED = 1
STATE_NOTIFIED = 2
STATE_ACKNOWLEDGED = 3
STATE_RESOLVED = 4
STATE_CANCELED = 5

# Error Types
TYPE_RESPONSE = 1
TYPE_QUESTION = 2
TYPE_SURVEY = 3
TYPE_ORDER = 4
TYPE_SLOT = 5
TYPE_REPORT = 6
TYPE_DOWNLOAD = 7

# Error Levels
LEVEL_DEBUG = 1
LEVEL_INFO = 2
LEVEL_WARN = 3
LEVEL_WARNING = 3
LEVEL_ERROR = 4
LEVEL_FATAL = 5

#------------------------------
# Email Notification bean
class Notification(object):
    """
    Simple class hierarchy to email various messages 
    types to predefined endpoints. 
    """
    
    # class defaults
    DEFAULT_SUBJ = "PspySSI: System Notification"
    try:
        DEFAULT_EMI = pspyConf.mailInfo
    except:
        DEFAULT_EMI = None
    DEFAULT_DBG_LEVEL = 1
    
    def __init__(self, emi=None, msg=None, sndr=None, rcvr=None, dbg=0):
        try:
            self._emi = emi or self.DEFAULT_EMI
            self._msg = msg
            self._subj = self.DEFAULT_SUBJ
            self._sender = sndr or self._emi.sender
            self._receiver = rcvr or self._emi.genNotification
            self._dbgLevel = dbg
            self._dump = True
        except:
            print "!! Ooops"
    # SMTP debug level property     
    # (affects logging verbosity on SMTP calls)
    def getDbgLevel(self):
        return self._dbgLevel
    def setDbgLevel(self, lvl):
        self._dbgLevel = lvl
    dbgLevel = property(getDbgLevel, setDbgLevel)
    
    # sender property
    def getSender(self):
        return self._sender
    def setSender(self, sndr):
        self._sender = sndr
    sender = property(getSender, setSender)

    # receiver property
    def getReceiver(self):
        return self._receiver
    def setReceiver(self, sndr):
        self._sender = sndr
    receiver = property(getSender, setSender)

    # subject property
    def getSubject(self):
        return self._subj
    def setSubject(self, subj):
        self._subj = subj
    subject = property(getSubject, setSubject)

    # test property sends message to log
    def getDump(self):
        return self._dump
    def setDump(self, flag=True):
        self._dump = flag
    test = property(getDump, setDump)
        
    def send(self, subject=None, txt=None):
        """
        Send a notification message.  
        """
        msg = txt or self._msg
        subj = subject or self._subj

        if not msg:
            raise Exception("Notification has no message to send")
    
        msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s" % (self.sender, self.receiver, subj, msg)
        
        if self.test:
            # debugging mode 
            print msg
        else:
            # send the message via SMTP 
            try:
                server = SMTP(self._emi.smtpServer)
                server.set_debuglevel(self.dbgLevel)
                server.sendmail(self.sender, self.receiver, msg)
                server.quit()
            except Exception, ex:
                # assume mail down or bad addr data and just log it
                print "!! Notification failure: %s (msg=%s)" % (str(ex), msg)        
                
    def setException(self, ex):
        """
        Parse up the exception and set up the messages
        """
        import sys
        
        # get exc info
        exx = sys.exc_info()
        tb = traceback.extract_tb(exx[2])[-1]
        try:
            etype = "!! Exception - %s: %s" % (str(exx[0]).split("'")[1], str(ex))
        except:
            etype = "!! Exception - %s" % str(ex)            

        # log exception trace...
        print etype
        tbm = '' 
        lmsg = ''
        for exc in traceback.extract_tb(exx[2]):
            tbm = "  => %s > Line %s (in %s)\n\t==> %s" % exc
            lmsg = " %s" % exc[-1]
            print tbm
            
        print "  => End \n"
        
        self.error = "%s: (%s)" % (etype.split(' - ')[1], lmsg.strip())

    def setMessage(self, msg):
        """
        Differentiate b/w strings and exceptions.
        """
        m = str(msg)
        if isinstance(msg, Exception):
            # exceptions always rate at least
            # a warning level message 
            self.setException(msg)
            if self.level < self.LEVEL_WARN:
                self.level = self.LEVEL_WARN
            m = "Exception: %s" % m
        
        # set attribute
        self.message = m
            
    def notify(self):
        """
        Send out notification for survey
        system error events.
        """
        # apply lables
        sts = self.ERROR_STATES[self.status]
        lvl = SurveyError.ERROR_LEVELS[self.level]
        typ = SurveyError.ERROR_TYPES[self.type]
        tms = self.tmstmp.strftime("%Y-%m-%d %H:%M:%S")
        

        # format message
        msg = "%s Error Notification <%s: Level=%s Status=%s>\n" % (typ, tms, lvl, sts)
        msg = "%s%s" % (msg, self.message)
        
        # get Notification bean
        n = Notification()

        # check for error notifications
        if lvl > self.LEVEL_INFO:
            # send to error notification end point(s)
            n.sender = pspyConf.mailInfo.errNotification

            # send out notification
            subject = "PspyWorx Notification <%s>" % (n.subject)
            n.send(txt=msg)
            self.status = self.STATE_NOTIFIED
